'''
Description: 
Author: Zilu
Date: 2021-11-10 14:50:35
Version: 
LastEditTime: 2021-11-10 15:18:41
LastEditors: Zilu
'''

# python的多线程是真正的posix thread，不是模拟出来的线程
# _thread 是低级模块，threading是对_thread的高级封装
import time, threading

# 新线程执行的代码
def loop():
    print('thread %s is running...' % (threading.current_thread().name))
    n = 0
    while n < 5:
        n += 1
        print('thread %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(1)
    print('thread %s ended.' % threading.current_thread().name)

print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)

# 多线程和多进程最大的不同在于，多进程中，同一个变量，各自有一份拷贝存在于每个进程中，互不影响，
# 而多线程中，所有变量都由所有线程共享，所以，任何一个变量都可以被任何一个线程修改，
# 因此，线程之间共享数据最大的危险在于多个线程同时改一个变量，把内容给改乱了。
# 可以用 Lock 避免
import threading

balance = 0
lock = threading.Lock()

def changeIt(n):
    global balance
    balance += n
    balance -= n

def runThread(n):
    for i in range(2000000):
        lock.acquire()
        try:
            changeIt(n)
        finally:
            lock.release()

t1 = threading.Thread(target=runThread, args=(5,))
t2 = threading.Thread(target=runThread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

# Python的线程虽然是真正的线程，但解释器执行代码时，有一个GIL锁：Global Interpreter Lock，
# 任何Python线程执行前，必须先获得GIL锁，
# 然后，每执行100条字节码，解释器就自动释放GIL锁，让别的线程有机会执行。
# 这个GIL全局锁实际上把所有线程的执行代码都给上了锁，
# 所以，多线程在Python中只能交替执行，即使100个线程跑在100核CPU上，也只能用到1个核。
import multiprocessing

def loop():
    x = 0
    while True:
        x = x ^ 1

for i in range(multiprocessing.cpu_count()):
    t = threading.Thread(target=loop)
    t.start()

# 这是解释器的遗留问题，目前使用的是 CPython 解释器，要利用真正的多核，除非重写一个不带 GIL 的解释器
# 要真正有效利用多核，最好还是用多进程


